﻿using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections;
using log4net;
using log4net.Config;
using System.Data.SQLite;
using ConfigFiles;
using MainServer;
using System.Text.RegularExpressions;
using Entity;
using Datas;
using immortal_c_.map;
using Map;
using System.Configuration;

#pragma warning disable CS8625 // 无法将 null 字面量转换为非 null 的引用类型。

[assembly: XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]

namespace MainServer
{
    internal class Server
    {
        public static Dictionary<string, Player> users = [];
        public static Dictionary<string, string> settings = [];
        public static readonly ILog logger = LogManager.GetLogger("Server");
        static readonly string CONFIG_PATH = Convert.ToString(AppDomain.CurrentDomain.BaseDirectory) + "config.ini";
        static readonly string locateIP = "127.0.0.1";
        static readonly int locatePort = 23112;
        static readonly IPAddress locateIpAddr = IPAddress.Parse(locateIP);
        static readonly IPEndPoint locatePoint = new IPEndPoint(locateIpAddr, locatePort);
        public static UdpClient udpClient = new UdpClient(locatePoint);
        static IPEndPoint remotePoint = new IPEndPoint(IPAddress.Parse("1.1.1.1"), 1);

        static readonly public string rootPath = Directory.GetCurrentDirectory();
        static readonly public Dictionary<string, Map.BaseMap> Maps = MapInitializer.InitializeMaps();

        private static void Main(string[] args)
        {
            Thread main_thread = new(MainThread_);
            Thread input_thread = new(InputThread);
            input_thread.Start();
            main_thread.Start();

        }
        static private void SendToClient(string message, IPEndPoint remotePoint)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(message);
            udpClient.Send(buffer, remotePoint);
        }
        /// <summary>
        /// 判断字符串全部是否是中文。返回false 则表示含有非中文
        /// </summary>
        /// <param name="str_chinese"></param>
        /// <returns>若全部为中文则true，否则false</returns>
        static public bool IsChinese(string str_chinese)
        {
            bool isItChinese = true;
            for (int i = 0; i < str_chinese.Length; i++)
            {
                Regex reg = new(@"[\u4e00-\u9fa5]");
                if (!reg.IsMatch(str_chinese[i].ToString()))
                {
                    isItChinese = false;
                    break;
                }
            }

            return isItChinese;

        }

        private static async void MainThread_()
        {
            logger.Info($"运行路径：{rootPath}");
            XmlConfigurator.Configure(); //log4net初始化
            // 服务端初始化
            if (!File.Exists(CONFIG_PATH))
            //判断是否存在config文件，没有就创建一个
            {
                FileStream fs = File.Create(CONFIG_PATH);
                fs.Close();
                ConfigINI.INIWrite("Database", "synchronous", "FULL", CONFIG_PATH);
                ConfigINI.INIWrite("Map", "default_dimension", "Hub", CONFIG_PATH);
                ConfigINI.INIWrite("Map", "default_x", "5", CONFIG_PATH);
                ConfigINI.INIWrite("Map", "default_y", "5", CONFIG_PATH);
                ConfigINI.INIWrite("Map", "view_range", "2", CONFIG_PATH);
                settings.Add("synchronous", ConfigINI.INIRead("DataBase", "synchronous", CONFIG_PATH));
                settings.Add("default_dimension", ConfigINI.INIRead("Map", "default_dimension", CONFIG_PATH));
                settings.Add("default_x", ConfigINI.INIRead("Map", "default_x", CONFIG_PATH));
                settings.Add("default_y", ConfigINI.INIRead("Map", "default_y", CONFIG_PATH));
                settings.Add("view_range", ConfigINI.INIRead("Map", "view_range", CONFIG_PATH)); //创建config后读取相关配置
            }
            else
            {
                settings.Add("synchronous", ConfigINI.INIRead("DataBase", "synchronous", CONFIG_PATH));
                settings.Add("default_dimension", ConfigINI.INIRead("Map", "default_dimension", CONFIG_PATH));
                settings.Add("default_x", ConfigINI.INIRead("Map", "default_x", CONFIG_PATH));
                settings.Add("default_y", ConfigINI.INIRead("Map", "default_y", CONFIG_PATH));
                settings.Add("view_range", ConfigINI.INIRead("Map", "view_range", CONFIG_PATH));
                logger.Info($"数据库synchronous模式已设为：{ConfigINI.INIRead("DataBase", "synchronous", CONFIG_PATH)}");
            }
            DataBase.InitializeDB();
            logger.Info("数据库初始化完毕");
            byte[] received;

            //test();
            // 循环接收数据
            for (; ; )
            {
                try
                {
                    received = udpClient.Receive(ref remotePoint);
                }
                catch (SocketException ex)
                {
                    logger.Error(ex);
                    continue;
                }
                string message = Encoding.UTF8.GetString(received); // 获取消息
                string client_addr = $"{remotePoint.Address}:{remotePoint.Port}"; // 获取地址
                if (message == "exit")
                //判断信息是否为exit
                {
                    if (users.ContainsKey(client_addr))
                    {
                        Player player_ = users[client_addr]; //获取玩家实例
                        logger.Info($"玩家{player_.UID} [{player_.Account}]退出了游戏");
                        users.Remove(client_addr); // 从users中删除对应键值对，并复制一份玩家实例
                        continue;
                    }
                }
                else if (string.IsNullOrEmpty(message) || message == " ") { continue; }// 若发送的信息为空就跳过
                else if (!users.ContainsKey(client_addr) && message == "connect")
                //若users中不存在client_addr键且尝试连接
                {
                    users.Add(
                        client_addr, new Player(new(remotePoint.Address, remotePoint.Port), "unknown")
                        ); // 向users中添加player实例，状态为login
                           // 注：此处需要new一个与remotePoint相同的IPEndPoint
                    SendToClient("000", remotePoint); //(特殊-连接成功！)
                    logger.Info($"已与[{client_addr}]建立连接......");
                    continue;
                }
                else if (users.ContainsKey(client_addr) && message == "login")
                // 信息为login
                {
                    users[client_addr].Status = "login_account";
                    byte[] buffer = Encoding.UTF8.GetBytes("001"); //(登录-输入账户名)
                    udpClient.Send(buffer, remotePoint);
                    logger.Info($"[{client_addr}] 正在尝试登陆......");
                    continue;
                }
                else if (users.ContainsKey(client_addr) && message == "reg")
                // 若users中存在client键且信息为reg
                {
                    users[client_addr].Status = "reg_account";
                    byte[] buffer = Encoding.UTF8.GetBytes("003"); //(注册-输入账户名)
                    udpClient.Send(buffer, remotePoint);
                    logger.Info($"[{client_addr}] 正在尝试注册......");
                    continue;
                }
                if (users.ContainsKey(client_addr))//若玩家在users里
                {
                    Player player = users[client_addr];
                    if (message == "reg") //结束进行的流程，转为注册
                    {
                        player.ResetPlayer(); //重置player
                        player.Status = "reg_account";
                        byte[] buffer = Encoding.UTF8.GetBytes("003"); //(注册-输入账户名)
                        udpClient.Send(buffer, remotePoint);
                        logger.Debug($"[{client_addr}] 终止流程，转为注册");
                    }
                    else if (message == "login") //结束正在进行的流程，转为登录
                    {
                        player.ResetPlayer(); //重置player
                        player.Status = "login_account";
                        byte[] buffer = Encoding.UTF8.GetBytes("001"); //(登录-输入账户名)
                        udpClient.Send(buffer, remotePoint);
                        logger.Debug($"[{client_addr}] 终止流程，转为登录");
                    }
                    else if (player.Status == "login_account") //状态：登录-输入账户名
                    {
                        if (await DataBase.IsUserExists(message))
                        {
                            long uid = await DataBase.GetUID(message);
                            string password = await DataBase.GetPassword(message) ?? "";
                            player.Status = "login_password";
                            player.Password = password;
                            player.UID = uid;
                            player.Account = message;
                            byte[] buffer = Encoding.UTF8.GetBytes("010"); //(登录-输入密码)
                            logger.Debug($"[{client_addr}] 正在尝试以 [{message}]{player.UID} 账户登录");
                            udpClient.Send(buffer, remotePoint);
                        }
                        else
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("110"); //(错误-登录-查无此人)
                            udpClient.Send(buffer, remotePoint);
                        }
                    }
                    else if (player.Status == "reg_account") //状态：注册-输入账户名
                    {
                        if (!await DataBase.IsUserExists(message))
                        {
                            player.Account = message;
                            player.Status = "reg_password";
                            byte[] buffer = Encoding.UTF8.GetBytes("011"); //(注册-第一次输入密码)
                            udpClient.Send(buffer, remotePoint);
                        }
                        else
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("111"); //(错误-注册-重名！)
                            udpClient.Send(buffer, remotePoint);
                        }
                    }
                    else if (player.Status == "login_password") //状态：登录-输入密码
                    {
                        if (message == player.Password) //判断密码是否正确
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("002"); //(登录-登陆成功)
                            logger.Info($"玩家{player.UID}[{player.Account}] 登陆成功");
                            udpClient.Send(buffer, remotePoint);
                            if (await DataBase.IsCharacterExists(player.UID)) // 判断账户下是否有角色
                            { //有角色
                                player.Status = "choose_character";
                                buffer = Encoding.UTF8.GetBytes($"008|{{{DataBase.GetStringCharactersOfUID(player.UID)}}}"); //(角色-选择)
                                udpClient.Send(buffer, remotePoint);
                            }
                            else //没有角色
                            {
                                player.Status = "create_character";
                                buffer = Encoding.UTF8.GetBytes("006"); //(角色-创建)
                                udpClient.Send(buffer, remotePoint);
                            }
                        }
                        else //密码错误
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("101"); //(登录-密码错误)
                            logger.Info(
                            $"玩家{player.UID}[{player.Account}] 登陆失败 (输入密码:{message};实际密码:{player.Password})"
                            );
                            udpClient.Send(buffer, remotePoint);
                        }
                    }
                    else if (player.Status == "reg_password")
                    {
                        if (!message.Contains(' '))
                        {
                            player.Password = message;
                            player.Status = "reg_password_again";
                            byte[] buffer = Encoding.UTF8.GetBytes("004"); //(注册-再次输入密码)
                            udpClient.Send(buffer, remotePoint);
                        }
                        else
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("112"); //(注册-密码不符合规范)
                            udpClient.Send(buffer, remotePoint);
                        }
                    }
                    else if (player.Status == "reg_password_again")
                    {
                        if (message == player.Password)
                        {
                            DataBase.AddUser(player.Account, player.Password);
                            long UID = await DataBase.GetUID(player.Account); //注：此处流程是注册，一定存在账户，所以无需进行账户不存在情况处理
                            player.UID = UID;
                            player.Status = "create_character";
                            byte[] buffer = Encoding.UTF8.GetBytes("005"); //(注册-注册成功)
                            udpClient.Send(buffer, remotePoint);
                            buffer = Encoding.UTF8.GetBytes("006"); //(角色-创建)
                            udpClient.Send(buffer, remotePoint);
                        }
                        else
                        {
                            player.Password = string.Empty;
                            player.Status = "reg_password";
                            byte[] buffer = Encoding.UTF8.GetBytes("112"); //(注册-两次密码不一致)
                            udpClient.Send(buffer, remotePoint);
                        }
                    }
                    else if (player.Status == "choose_character")
                    {
                        if (message == "new")
                        {
                            player.Status = "create_character";
                            byte[] buffer = Encoding.UTF8.GetBytes("006"); //(角色-创建角色)
                            udpClient.Send(buffer, remotePoint);
                            continue;
                        }
                        int.TryParse(message, out int cid); //将message(string)转换为int
                        if (cid.GetType() == typeof(int) && await DataBase.IsCharacterExists(player.UID, cid))
                        {

                            player.CharacterId = cid;
                            player.CharacterName = await DataBase.GetCharacterName(player.UID, cid);
                            player.Status = "online";
                            Dictionary<string, double> attributes = await DataBase.GetAllAttributes(player.UID, player.CharacterId);
                            // 选择角色后获取角色对应属性
                            byte[] buffer = Encoding.UTF8.GetBytes($"009|{player.CharacterName}"); //(角色-选择完毕，进入游戏)
                            udpClient.Send(buffer, remotePoint);
                        }
                        else
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("105"); //(角色-角色id超出范围)
                            udpClient.Send(buffer, remotePoint);
                        }
                    }
                    else if (player.Status == "create_character")
                    {
                        string character_name = message;
                        if (IsChinese(character_name))
                        {
                            long CID = await DataBase.AddCharacter(player.UID, character_name);
                            player.CharacterId = CID;
                            player.CharacterName = character_name;
                            player.Status = "online";
                            var attributes = DataBase.GetAllAttributes(player.UID, player.CharacterId);

                            byte[] buffer = Encoding.UTF8.GetBytes("007"); //(角色-创建成功，进入游戏)
                            udpClient.Send(buffer, remotePoint);
                        }
                        else
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("104"); //(角色-名称不符合标准)
                            udpClient.Send(buffer, remotePoint);
                        }
                    }
                    else if (message == "hp" || message == "attribute" || message == "hud" || message == "attr")
                    {
                        byte[] buffer = Encoding.UTF8.GetBytes($@"204|{{{player.GetAllAttributesString()}}}"); //204(指令-获取所有状态)
                        udpClient.Send(buffer, remotePoint);
                    }
                    else if (message.Contains("say ")) // say指令
                    {
                        string[] text = message.Split(" ", 2); //将消息以空格分隔，最多分割一次（2指分割后的字符串数量）
                        if (text[1] != string.Empty)
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes($@"201|{player.CharacterName}|{text[1]}");
                            foreach (Player player_ in users.Values) //用player_遍历users.Values（Dictionary<string,Player>）
                            {
                                udpClient.Send(buffer, player_.Addr); //发送到每个玩家
                            }
                        }
                    }
                    else if (message == "map")
                    {
                        BaseMap map = Maps[player.Dimension];
                        string json_map = map.GetSizedMapOfJson(player.Position, int.Parse(settings["view_range"]));
                        byte[] buffer = Encoding.UTF8.GetBytes($"205|{json_map}");
                        udpClient.Send(buffer, remotePoint);
                    }
                    else//无特殊
                    {
                        logger.Info($"[{client_addr}]{player.Account}:{message}"); //打印消息
                    }

                }

            }

        }
        private static void InputThread()
        {
            string? command;
            for (; ; )
            {
                command = Console.ReadLine();
                if (command == null)
                {
                    continue;
                }
                else
                {
                    if (command.ToLower() == "exit" || command.ToLower() == "stop")
                    {
                        logger.Info("五秒后退出服务器......");
                        Thread.Sleep(5000);
                        Environment.Exit(Environment.ExitCode);
                    }
                    else if (command.StartsWith("map "))
                    {
                        string appointted_map = command.Split(' ', 3)[1];
                        if (Maps.TryGetValue(appointted_map, out BaseMap? value))//若Map字典中包含该地图
                        {
                            BaseMap map = value; //获取地图
                            try
                            {
                                int size = int.Parse(command.Split(' ', 3)[2]);
                                logger.Info($"\n{map.GetSizedMapOfJson(size)}");
                            }
                            catch (IndexOutOfRangeException)
                            {

                                logger.Info($"\n{map.GetMapOfJson()}");
                            }
                        }
                        else
                        {
                            logger.Warn("不存在该地图!");
                        }
                    }
                }
                logger.Info($"您输入了：{command}");
            }
        }

    }
}




public delegate void DelegateFunc(ref Player player);

namespace Items
{
    public class BaseItem
    {
        public int Amount { get; set; } = 0;
        public string Name { get; set; } = string.Empty;
        public string Profile { get; set; } = string.Empty;
        public string Introduction { get; set; } = string.Empty;
        public int Weight { get; set; } = 0;
        public string Id { get; set; } = string.Empty;
        public bool Useable { get; set; } = false; //是否可使用，默认为否
        public Dictionary<string, DelegateFunc> Actions { get; set; } = []; //操作列表
        public string Rarity { get; set; } = string.Empty;
        public bool Execute(string name, ref Player player)
        {
            if (Actions.ContainsKey(name))
            {
                Actions[name](ref player);
                return true;
            }
            else
            {
                return false;
            }
        }
    }
    static class EmptyItem //空物品
    {
        static public int Amount { get; set; } = 0;
        static public string Name { get; set; } = string.Empty;
        static public string Profile { get; set; } = string.Empty;
        static public string Introduction { get; set; } = string.Empty;
        static public int Weight { get; set; } = 0;
        static public string Id { get; set; } = string.Empty;
        static public bool Useable { get; set; } = false;
    }
    class WeaponItem : BaseItem
    {
        public double attack = 0; //武器攻击力
        public DelegateFunc[] special_effects = []; //武器特殊效果
        public double Attack { get { return attack; } set { attack = value; } }
        public DelegateFunc[] SpecialEffects { get { return special_effects; } set { special_effects = value; } }
        public new Dictionary<string, DelegateFunc> Actions { get; set; } = new() { { "equip", new DelegateFunc(Equip) } }; //添加到Acitons中
        /// <summary>
        /// 装备上该武器
        /// </summary>
        /// <param name="player">玩家实例</param>
        static public void Equip(ref Player player)
        {

        }
    }
}

namespace Map

{

    namespace Plot
    {
        class BasePlot //基础地块
        {
            public string Name { get; set; } = string.Empty;
            public string Profile { get; set; } = string.Empty;
            public string Introduction { get; set; } = string.Empty;
            public Unit.BaseUnit[] Units { get; set; } = [];
            public bool IsEnterable { get; set; } = true; //是否可进入，默认为是
            public bool IsProtal { get; set; } = false; //是否可进入，默认为否
            public int[] Destination { get; set; } = new int[2];
        }
    }
    namespace Unit
    {
        class BaseUnit
        {
            public string UnitType { get; set; } = "BaseUnit";
            public int amount = 0; //单位数量
            public string Name { get; set; } = string.Empty;
            public string Profile { get; set; } = string.Empty;
            public string Introduction { get; set; } = string.Empty;
            public int Amount { get { return amount; } set { amount = value; } }
            public Dictionary<string, DelegateFunc> Actions { get; set; } = [];
            public bool Execute(string name, ref Player player)
            {
                if (Actions.ContainsKey(name))
                {
                    Actions[name](ref player);
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    }
    class BaseMap
    {
        public string Name { get; set; } = string.Empty;
        public int X_Max { get; set; }
        public int Y_Max { get; set; }
        public Plot.BasePlot[,] WorldMap { get; set; }
        /// <summary>
        /// 地图的构造函数，传入x，y建立一个空白地图
        /// </summary>
        /// <param name="limit_x">x上限</param>
        /// <param name="limit_y">y上限</param>
        public BaseMap(int limit_x = 0, int limit_y = 0)
        {

            X_Max = limit_x; //此处默认为0是为了通过编译器
            Y_Max = limit_y;
            WorldMap = new Plot.BasePlot[X_Max, Y_Max];

        }

        /// <summary>
        /// 获取限制范围后的地图，超出范围即为emptyPlot
        /// </summary>
        /// <param name="position">当前玩家位置，顺序为{x,y}</param>
        /// <param name="extend_x">x方向边界到中心点的垂直距离</param>
        /// <param name="extend_y">y方向边界到中心点的垂直距离</param>
        /// <returns>Plot.BasePlot二维数组，长度为(2*extend_x)+1, (2*extend_y)+1</returns>
        public Plot.BasePlot[,] GetSizedMap(int[] position, int extend_x, int extend_y)
        {
            Plot.BasePlot[,] sized_map = new Plot.BasePlot[(2 * extend_x) + 1, (2 * extend_y) + 1]; //创建对应范围的地图
            for (int x = position[0] - extend_x; position[0] - extend_x <= x && x <= position[0] + extend_x; x++)
            {
                for (int y = position[1] - extend_y; position[1] - extend_y <= y && y <= position[1] + extend_y; y++)
                {
                    if (x <= 0 || x >= X_Max || y <= 0 || y >= Y_Max) //若任意一个坐标超出边界
                    {
                        sized_map[x, y] = null; //即为空
                    }
                    else
                    {
                        sized_map[x, y] = WorldMap[x, y];
                    }
                }
            }
            return sized_map;
        }
        /// <summary>
        /// 获取限制范围后的地图，超出范围即为null
        /// </summary>
        /// <param name="position">中心点数组，顺序为{x,y}</param>
        /// <param name="range">中心点到边界任意一点的垂直距离（正方形）</param>
        /// <returns>Plot.BasePlot二维数组，长度为(2*range)+1, (2*range)+1</returns>
        public Plot.BasePlot[,] GetSizedMap(int[] position, int range)
        {
            Plot.BasePlot[,] sized_map = new Plot.BasePlot[(2 * range) + 1, (2 * range) + 1]; //创建对应范围的地图
            for (int x = position[0] - range; position[0] - range <= x && x <= position[0] + range; x++)
            {
                for (int y = position[1] - range; position[1] - range <= y && y <= position[1] + range; y++)
                {
                    if (x <= 0 || x >= X_Max || y <= 0 || y >= Y_Max) //若任意一个坐标超出边界
                    {
                        sized_map[x, y] = null; //即为空
                    }
                    else
                    {
                        sized_map[x, y] = WorldMap[x, y];
                    }
                }
            }
            return sized_map;
        }
        /// <summary>
        /// 获取限制范围后的地图字符串，超出范围即为string.Empty
        /// </summary>
        /// <param name="position">当前玩家位置，顺序为{x,y}</param>
        /// <param name="range">中心点到边界任意一点的垂直距离（正方形）</param>
        /// <returns>string二维数组，长度为(2*range)+1, (2*range)+1</returns>
        public string[,] GetSizedMapOfString(int[] position, int range)
        {
            string[,] sized_map = new string[(2 * range) + 1, (2 * range) + 1]; //创建对应范围的地图
            // 此处range为半径， 额外+1是由于玩家所在中心点坐标
            for (int x = position[0] - range; position[0] - range <= x && x <= position[0] + range; x++)
            {
                for (int y = position[1] - range; position[1] - range <= y && y <= position[1] + range; y++)
                {
                    if (x <= 0 || x >= X_Max || y <= 0 || y >= Y_Max) //若任意一个坐标超出边界
                    {
                        sized_map[x, y] = string.Empty; //即为空
                    }
                    else
                    {
                        sized_map[x, y] = WorldMap[x, y].Name;
                    }
                }
            }
            return sized_map;
        }
        /// <summary>
        /// 获取string[,]化的地图（一般没啥用）
        /// </summary>
        /// <returns>字符串二维数组</returns>
        public string[,] GetMapOfString()
        {
            string[,] map = new string[X_Max + 1, Y_Max + 1];
            for (int x = 0; x <= X_Max; x++)
            {
                for (int y = 0; y <= Y_Max; y++)
                {
                    if (WorldMap[x, y] is null)
                    {
                        map[x, y] = string.Empty;
                        continue;
                    }
                    map[x, y] = WorldMap[x, y].Name;
                }
            }
            return map;
        }
        /// <summary>
        /// 获取Json化的地图
        /// </summary>
        /// <returns>Json字符串，格式为[[...,...],[...,...],...]</returns>
        public string GetMapOfJson()
        {
            string map = "[";
            for (int x = 0; x <= X_Max; x++)
            {
                map += "[";
                for (int y = 0; y <= Y_Max; y++)
                {
                    if (WorldMap[x, y] is null)
                    {
                        map += @""""","; //增加空字符串
                        continue;
                    }
                    map += @$"""{WorldMap[x, y].Name}"",";
                }
                map = map.TrimEnd(','); //去除末尾逗号
                map += "],\n";
            }
            map = map.TrimEnd('\n'); //去除末尾\n
            map = map.TrimEnd(','); //去除末尾逗号
            map += "]";
            return map;
        }
        /// <summary>
        /// 获取Json化的范围内地图
        /// </summary>
        /// <param name="position">当前玩家位置，顺序为[x,y]</param>
        /// <param name="range">边界到中心点的垂直距离</param>
        /// <returns>Json字符串，格式为[[...,...],[...,...],...]</returns>
        public string GetSizedMapOfJson(int[] position, int range)
        {
            string sized_map = "["; //Json二维数组格式：[[...],[...],...]
            for (int x = position[0] - range; position[0] - range <= x && x <= position[0] + range; x++)
            {
                sized_map += "[";
                for (int y = position[1] - range; position[1] - range <= y && y <= position[1] + range; y++)
                {
                    if (x <= 0 || x >= X_Max || y <= 0 || y >= Y_Max || WorldMap[x, y] is null) //若任意一个坐标超出边界
                    {
                        sized_map += @""""","; //即为 "",
                    }
                    else
                    {
                        sized_map += @$"""{WorldMap[x, y].Name}"",";
                    }
                }
                sized_map = sized_map.TrimEnd(','); //去除末尾逗号
                sized_map += "],";
            }
            sized_map = sized_map.TrimEnd(','); //去除末尾逗号
            sized_map += "]";
            return sized_map;
        }
        /// <summary>
        /// 获取Json化的范围内地图
        /// </summary>
        /// <param name="position">当前玩家位置，顺序为[x,y]</param>
        /// <param name="range">边界到中心点的垂直距离</param>
        /// <returns>Json字符串，格式为[[...,...],[...,...],...]</returns>
        public string GetSizedMapOfJson(int range)
        {
            int[] position = [X_Max / 2, Y_Max / 2];
            string sized_map = "["; //Json二维数组格式：[[...],[...],...]
            for (int x = position[0] - range; position[0] - range <= x && x <= position[0] + range; x++)
            {
                sized_map += "[";
                for (int y = position[1] - range; position[1] - range <= y && y <= position[1] + range; y++)
                {
                    if (x <= 0 || x >= X_Max || y <= 0 || y >= Y_Max || WorldMap[x, y] is null) //若任意一个坐标超出边界
                    {
                        sized_map += @""""","; //即为 "",
                    }
                    else
                    {
                        sized_map += @$"""{WorldMap[x, y].Name}"",";
                    }
                }
                sized_map = sized_map.TrimEnd(','); //去除末尾逗号
                sized_map += "],";
            }
            sized_map = sized_map.TrimEnd(','); //去除末尾逗号
            sized_map += "]";
            return sized_map;
        }
    }
}

namespace Datas
{
    static class DataBase
    {
        static SQLiteConnection? conn;
        static string? sql;
        static SQLiteCommand? command;
        static public void ConnectToDB()
        {
            conn = new SQLiteConnection("Data Source=saves.db;Version=3;");
            conn.Open();
        }
        /// <summary>
        /// 初始化数据库（创建表等）
        /// </summary>
        static public void InitializeDB()
        {
            ConnectToDB();
            string synchronous;
            try
            {
                synchronous = Server.settings["synchronous"];
            }
            catch (KeyNotFoundException) //若无此键
            {
                synchronous = "FULL";
            }
            ExecuteSQLCommand($"PRAGMA synchronous = {synchronous};");
            ExecuteSQLCommand("BEGIN;");
            sql = "CREATE TABLE IF NOT EXISTS users(uid integer primary key autoincrement,account text NOT NULL,password text NOT NULL);";
            ExecuteSQLCommand(sql);
            sql = "INSERT OR IGNORE INTO users values (10000000,'test','111');";
            ExecuteSQLCommand(sql);
            sql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_users_uid on users (uid);";
            ExecuteSQLCommand(sql);
            sql = "CREATE TABLE IF NOT EXISTS 'attribute' ('uid' INTEGER NOT NULL,'cid' INTEGER NOT NULL,'hp_max' REAL NOT NULL DEFAULT 200,'hp' REAL NOT NULL DEFAULT 200,'mp_max' REAL NOT NULL DEFAULT 50,'mp' REAL NOT NULL DEFAULT 50,'atk' REAL NOT NULL DEFAULT 10,'def' REAL NOT NULL DEFAULT 10,'crit' REAL NOT NULL DEFAULT 0.01,'crit_damage' REAL NOT NULL DEFAULT 1.5,'dex' REAL NOT NULL DEFAULT 0.9,'pot' REAL NOT NULL DEFAULT 0,'lv' INTEGER NOT NULL DEFAULT 1,'exp' REAL NOT NULL DEFAULT 0,'exp_max' REAL NOT NULL DEFAULT 10);";
            ExecuteSQLCommand(sql);
            sql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_attribute_uid_cid on attribute (uid,cid);";
            ExecuteSQLCommand(sql);
            sql = "CREATE TABLE IF NOT EXISTS 'character' ('uid' INTEGER,'cid' INTEGER,'character_name' TEXT);";
            ExecuteSQLCommand(sql);
            sql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_character_uid_cid on character (uid,cid);";
            ExecuteSQLCommand(sql);
            sql = "CREATE TABLE IF NOT EXISTS 'location' ('uid' INTEGER,'cid' INTEGER,'dimension' TEXT,'x' INTEGER,'y' INTEGER);";
            ExecuteSQLCommand(sql);
            sql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_location_uid_cid on location (uid,cid);";
            ExecuteSQLCommand(sql);
            ExecuteSQLCommand("COMMIT;");

        }

        static private async void ExecuteSQLCommand(string sql_)
        {
            command = new SQLiteCommand(sql_, conn);
            await command.ExecuteNonQueryAsync();
        }
        ///<Summary>
        ///执行SQL语句并获取一个reader
        ///</Summary>
        ///<remarks>
        ///注：
        ///<code>
        ///while(reader.Read())
        ///</code>
        ///这其中的语句只有当查询结果不为空集时才会执行
        ///</remarks>
        static private async Task<SQLiteDataReader> ExecuteSQLCommandForReaderAsync(string sql_)
        {
            command = new SQLiteCommand(sql_, conn);
            SQLiteDataReader reader = (SQLiteDataReader)await command.ExecuteReaderAsync();
            return reader;
        }
        /// <summary>
        /// 获取全部UID，返回一个UID_List
        /// </summary>
        /// <returns>返回一个UID列表</returns>
        static public async Task<List<int>> GetAllUID()
        {
            SQLiteDataReader UID_reader = await ExecuteSQLCommandForReaderAsync("SELECT uid FROM users;");
            List<int> UID_List = [];
            while (UID_reader.Read())
            {
                UID_List.Add((int)UID_reader["uid"]);
            }
            return UID_List;
        }
        /// <summary>
        /// 获取该账户的UID
        /// </summary>
        /// <param name="account_name">该账户账户名</param>
        /// <returns>若该账户存在则返回UID，若不存在则0</returns>
        static public async Task<long> GetUID(string account_name)
        {
            long uid = 0;
            SQLiteDataReader UID_reader = await ExecuteSQLCommandForReaderAsync($"SELECT uid FROM users WHERE account='{account_name}';");
            if (UID_reader.Read())
            {
                uid = (long)UID_reader["uid"];
            }
            return uid;
        }
        /// <summary>
        /// 获取该uid账户的密码
        /// </summary>
        /// <param name="uid">该账户UID</param>
        /// <returns>若有密码则返回密码，若没有则null</returns>
        static public async Task<string> GetPassword(int uid)
        {
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT password FROM users INDEXED BY idx_users_uid WHERE uid={uid};");
            string password = string.Empty;
            if (reader.Read())
            {
                password = (string)reader["password"];
            }
            return password;
        }
        /// <summary>
        /// 获取该账户的密码
        /// </summary>
        /// <param name="account">该账户账户名</param>
        /// /// <returns>若有密码则返回密码，若没有则null</returns>
        static public async Task<string> GetPassword(string account)
        {
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT password FROM users WHERE account='{account}';");
            string password = string.Empty;
            if (reader.Read())
            {
                password = (string)reader["password"];
            }
            return password;
        }
        /// <summary>
        /// 根据最后一名玩家的UID获取下一个UID
        /// </summary>
        /// <param name="UID">下一个UID</param>
        static public async Task<long> GetNextUID()
        {
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync("Select seq From sqlite_sequence Where name = 'users';");
            long UID = (long)reader["uid"] + 1;
            return UID;
        }
        /// <summary>
        /// 根据UID-CID获取玩家名称
        /// </summary>
        /// <remarks>若该UID-CID存在，则返回玩家名称，否则返回<c>string.Empty</c></remarks>
        /// <param name="uid"></param>
        /// <param name="cid"></param>
        /// <returns>玩家名称或<c>string.Empty</c></returns>
        static public async Task<string> GetCharacterName(long uid, long cid)
        {
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT character_name FROM character INDEXED BY idx_character_uid_cid WHERE uid={uid} AND cid = {cid};");
            string character_name = string.Empty;
            if (reader.Read())
            {
                character_name = (string)reader["character_name"];
            }
            return character_name;
        }
        /// <summary>
        /// 根据UID获取该玩家所有角色的CID列表
        /// </summary>
        /// <param name="uid"></param>
        /// <returns>玩家的CID列表</returns>
        static public async Task<List<long>> GetListOfCharacterIDs(long uid)
        {
            List<long> list_characterid = [];
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT cid FROM character WHERE uid={uid};");
            while (reader.Read())
            {
                list_characterid.Add((long)reader["cid"]);
            }
            return list_characterid;
        }
        /// <summary>
        /// 获取该UID下所有的角色
        /// </summary>
        /// <param name="uid">该账户的UID</param>
        /// <returns>返回一个<c>Dictionary[long,string]</c>，格式为<c>{CID:角色名,...}</c></returns>
        static public async Task<Dictionary<long, string>> GetAllCharactersOfUID(long uid)
        {
            Dictionary<long, string> character_dict = [];
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT cid,character_name FROM character WHERE uid={uid};");
            while (reader.Read())
            {
                character_dict.Add((long)reader["cid"], (string)reader["character_name"]);
            }
            return character_dict;
        }
        /// <summary>
        /// 获取该UID下的所有角色
        /// </summary>
        /// <example>
        /// <code>
        /// // 10000000-1:A;10000000-2:B,...
        /// string all_names = await GetStringCharacterOfUID(10000000);
        /// Console.WriteLine(all_names);
        /// >>>"1:'A',2:'B',..."
        /// </code>
        /// </example>
        /// <param name="uid">该账户的UID</param>
        /// <returns>返回一个字符串，内容为"角色ID:'角色名',..."</returns>
        static public async Task<string> GetStringCharactersOfUID(long uid)
        {
            string character_string = string.Empty;
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT cid,character_name FROM character WHERE uid={uid};");
            while (reader.Read())
            {
                long cid = (long)reader["cid"];
                string character_name = (string)reader["character_name"];
                character_string += $"{cid}:'{character_name}',";
            }
            return character_string;
        }
        static public async Task<Dictionary<string, double>> GetAllAttributes(long uid, long cid)
        {
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT * FROM attribute INDEXED BY idx_attribute_uid_cid WHERE uid={uid} AND cid={cid};");
            Dictionary<string, double> attributes = [];
            if (reader.Read())
            {
                attributes["Hp"] = (double)reader["hp"];
                attributes["HpMax"] = (double)reader["hp_max"];
                attributes["Mp"] = (double)reader["mp"];
                attributes["MpMax"] = (double)reader["mp_max"];
                attributes["Atk"] = (double)reader["atk"];
                attributes["Def"] = (double)reader["def"];
                attributes["Crit"] = (double)reader["crit"];
                attributes["CritDam"] = (double)reader["crit_damage"];
                attributes["Dex"] = (double)reader["dex"];
                attributes["Pot"] = (double)reader["pot"];
                attributes["Lv"] = (long)reader["lv"];
                attributes["Exp"] = (double)reader["exp"];
                attributes["ExpMax"] = (double)reader["exp_max"];
            }
            return attributes;
        }
        /// <summary>
        /// 根据账户名判断是否存在该账户
        /// </summary>
        /// <param name="account">账户名</param>
        /// <returns>存在为true，不存在为false</returns>
        static public async Task<bool> IsUserExists(string account)
        {
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT uid FROM users WHERE account='{account}';");
            if (reader.Read())
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 根据UID判断是否存在该账户
        /// </summary>
        /// <param name="uid"></param>
        /// <returns>存在为true，不存在为false</returns>
        static public async Task<bool> IsUserExists(long uid)
        {
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT account FROM users INDEXED BY idx_users_uid WHERE uid={uid};");
            if (reader.Read())
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 判断该UID下是否有角色
        /// </summary>
        /// <param name="uid"></param>
        /// <returns>存在为true，不存在为false</returns>
        static public async Task<bool> IsCharacterExists(long uid)
        {
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT character_name FROM character WHERE uid={uid};");
            if (reader.Read())
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        ///<summary>
        ///判断该UID下是否有CID的角色
        ///</summary>
        ///<param name="uid">想要查询的UID(用户ID)</param>
        ///<param name="cid">想要查询的CID(角色ID)</param>
        ///<returns>存在为true,不存在为false</returns>
        static public async Task<bool> IsCharacterExists(long uid, long cid)
        {
            SQLiteDataReader reader = await ExecuteSQLCommandForReaderAsync($"SELECT character_name FROM character INDEXED BY idx_character_uid_cid WHERE uid={uid} AND cid={cid};");
            if (reader.Read())
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 新增用户（注：此处已经过验证，不会重名）
        /// </summary>
        /// <param name="account">新增的用户名</param>
        /// <param name="password">新增用户的密码</param>
        static public void AddUser(string account, string password)
        {
            ExecuteSQLCommand(@$"INSERT INTO users (account,password) VALUES (""{account}"",""{password}"");");
        }
        /// <summary>
        /// 向数据库添加角色（自动处理CID）
        /// </summary>
        /// <param name="uid">账户UID</param>
        /// <param name="character_name">添加的角色名</param>
        static public async Task<long> AddCharacter(long uid, string character_name)
        {
            List<long> CID_list = await GetListOfCharacterIDs(uid); // 获取所有CID
            long next_CID;
            try
            {
                next_CID = CID_list.Max() + 1L; // 获取下一个CID
            }
            catch (InvalidOperationException)
            {
                next_CID = 1;
            }
            ExecuteSQLCommand("BEGIN;");
            ExecuteSQLCommand($"INSERT INTO character (uid,cid,character_name) VALUES ({uid},{next_CID},'{character_name}');");
            ExecuteSQLCommand($"INSERT INTO attribute (uid,cid) VALUES ({uid},{next_CID});");
            ExecuteSQLCommand($"INSERT INTO location (uid,cid,x,y,dimension) VALUES ({uid},{next_CID},{Server.settings["default_x"]},{Server.settings["default_y"]},'{Server.settings["default_dimension"]}');");
            ExecuteSQLCommand("COMMIT;");
            return next_CID;
        }
    }

}

